package com.fingard.dsp.bank.directbank.bocom13.util;

import java.lang.System;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

/**************************************************************************
 MAC值计算中的DES/3DES加密说明:

 1. 8字节密钥, 采用DES迭代加密MAC分组

 2. 16字节密钥(分为: 左8字节密钥, 右8字节密钥), 采用3DES.
 加密过程: 左部密钥迭代加密MAC分组(全部), 
 右部密钥解密上步结果, 
 左部密钥加密上步结果

 3. 24字节密钥(分为: 左8字节密钥, 中8字节密钥, 右8字节密钥), 采用3DES.
 加密过程: 左部密钥迭代加密MAC分组(全部), 
 中部密钥解密上步结果, 
 右部密钥加密上步结果
 **************************************************************************/

/**
 * 用来产生报文的MAC值 加密算法采用DES
 * 
 * @author fanghh
 * @date 2019/4/16
 */
public class Mac {
	// 产生MAC值时所用的加密算法
	private static final String ALOGRITHM = "DES/ECB/NoPadding";

	// 使用MAC KEY计算数据的MAC值,并转换成16进制字符串
	public static String generateMac(byte[] key, byte[] data) {
		int i = 0, j = 0, m = 0, n = 0;

		if (key.length != 8 && key.length != 16 && key.length != 24)
			return "0000000000000000";

		// 初始MAC值: 8个字节的0x00
		byte[] mac = new byte[8];
		for (i = 0; i < 8; i++)
			mac[i] = 0;

		try {
			// 构造密钥
			SecretKeySpec lKey = new SecretKeySpec(key, 0, 8, "DES");

			// 使用左半部密钥进行加密
			Cipher cipher = Cipher.getInstance(ALOGRITHM);
			cipher.init(Cipher.ENCRYPT_MODE, lKey);

			for (i = 0, m = ((data.length >> 3) << 3); i < m; i += 8) {
				for (j = 0; j < 8; j++)
					mac[j] = (byte) (mac[j] ^ data[i + j]);

				mac = cipher.doFinal(mac);
			}

			n = (data.length & 0x07);
			if (n > 0) {
				// 若最后数据块不足8个字节
				for (j = 0; j < n; j++)
					mac[j] = (byte) (mac[j] ^ data[i + j]);

				mac = cipher.doFinal(mac);
			}

			if (key.length == 16) {
				// 构造密钥
				SecretKeySpec rKey = new SecretKeySpec(key, 8, 8, "DES");

				// 使用右半部密钥进行解密
				cipher.init(Cipher.DECRYPT_MODE, rKey);
				mac = cipher.doFinal(mac);

				// 使用左半部密钥进行加密
				cipher.init(Cipher.ENCRYPT_MODE, lKey);
				mac = cipher.doFinal(mac);
			} else if (key.length == 24) {
				// 构造密钥
				SecretKeySpec mKey = new SecretKeySpec(key, 8, 8, "DES");
				SecretKeySpec rKey = new SecretKeySpec(key, 16, 8, "DES");

				// 使用中半部密钥进行解密
				cipher.init(Cipher.DECRYPT_MODE, mKey);
				mac = cipher.doFinal(mac);

				// 使用右半部密钥进行加密
				cipher.init(Cipher.ENCRYPT_MODE, rKey);
				mac = cipher.doFinal(mac);
			}

			return bytes2HexStr(mac);
		} catch (Exception e) {
			return "0000000000000000";
		}
	}

	/**
	 * 将16进制字符串转换成字节数组
	 * 
	 * @param hexstr
	 * @return
	 */
	public static byte[] hexStr2Bytes(String hexstr) {
		byte b[] = new byte[hexstr.length() >> 1];
		int j = 0;
		for (int i = 0; i < b.length; i++) {
			char c0 = hexstr.charAt(j++);
			char c1 = hexstr.charAt(j++);
			b[i] = (byte) (parse(c0) << 4 | parse(c1));
		}

		return b;
	}

	private static int parse(char c) {
		if (c >= 'a')
			return (c - 97) + 10 & 0x0F;
		if (c >= 'A')
			return (c - 65) + 10 & 0x0F;
		else
			return c - 48 & 0x0F;
	}

	/**
	 * 将字节数组转换成16进制字符串
	 * 
	 * @param b
	 * @return
	 */
	public static String bytes2HexStr(byte b[]) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < b.length; i++)
			sb.append(byteToHexString(b[i]));
		return sb.toString();
	}

	/**
	 * 将字节转换成16进制字符串
	 * 
	 * @param b
	 * @return
	 */
	private static String byteToHexString(byte b) {
		byte hex[] = "0123456789ABCDEF".getBytes();

		byte buff[] = new byte[2];
		buff[0] = hex[b >> 4 & 0x0F];
		buff[1] = hex[b & 0x0F];

		return new String(buff);
	}

	public static void main(String[] args) throws Exception {
		byte data[] = "test-mac1".getBytes();

		String stKey24 = "3D7595A98BFF809D70A2718E2D0A042F2963347B392FDE7C";
		String stKey16 = "70A2718E2D0A042F2963347B392FDE7C";
		String stKey08 = "2963347B392FDE7C";

		byte key24[] = hexStr2Bytes(stKey24);
		byte key16[] = hexStr2Bytes(stKey16);
		byte key08[] = hexStr2Bytes(stKey08);

		String mac24 = Mac.generateMac(key24, data);
		String mac16 = Mac.generateMac(key16, data);
		String mac08 = Mac.generateMac(key08, data);

		System.out.println("24-->[" + mac24 + "]");
		System.out.println("16-->[" + mac16 + "]");
		System.out.println("08-->[" + mac08 + "]");
	}
}
